package com.qixiao.lib.generic.wildcard;

/**
 * 通配符 ？ 未知的类型
 * ? extends 或者 ？ super 限定类型范围
 * 不能用在泛型类声明上
 */
public class Wildcard {

    public static void print(GenericType<Fruit> g) {
        System.out.println(g.getData().toString());
    }

    public static void use() {
        GenericType<Fruit> a = new GenericType<>();
        print(a);
        GenericType<Apple> b = new GenericType<>();
//        print(b);//报错，为啥水果泛型可以 我苹果泛型就不行了， 这就引出了通配符概念解决这个问题
    }

    //<? extends Fruit>上界通配符 安全的读数据
    //为啥要叫上界， 对于apple和Bannana来说 Fruit是父亲在我之上
    //从继承关系图来看，向下可以是Fruit或Fruit的任何子类，但是向上不能突破Fruit 所以这个称之为上界通配符
    public static void print1(GenericType<? extends Fruit> g) {
        System.out.println(g.getData().toString());
    }

    public static void use1() {
        GenericType<Fruit> a = new GenericType<>();
        print1(a);
        GenericType<Apple> b = new GenericType<>();
        print1(b);
//        print1(new GenericType<Food>());//报错了， 不能突破到Food, 应为上界值是Fruit

        GenericType<? extends Fruit> c = new GenericType<>();
        GenericType<? extends Fruit> c1 = new GenericType<Fruit>();
        GenericType<? extends Fruit> c2 = new GenericType<Apple>();
        GenericType<? extends Fruit> c3 = new GenericType<Hongfushi>();
        Apple apple = new Apple();
        Fruit fruit = new Fruit();
        //编译知道你的上界是Fruit, 但是不知道你的具体类型，所以c.setData报错
//        c.setData(apple);//报错
//        c.setData(fruit);//报错

        //因为c接收的泛型类型值是Fruit子类型，拿出来的肯定是个Fruit
        Fruit f1 = c.getData();
    }

    //<? super Apple>下界通配符  安全写入数据
    //为啥要叫下界， 对于Fruit来说 apple在Fruit下面
    //从继承关系图来看，向上可以是Apple或Apple的任何父类，但是向下不能突破Apple， 所以这个称之为下界通配符
    public static void print2(GenericType<? super Apple> g) {
        System.out.println(g.getData().toString());
    }

    public static void use2() {
        GenericType<Fruit> a = new GenericType<>();
        a.setData(new Apple());
        a.setData(new Fruit());
        print2(a);
        GenericType<Apple> b = new GenericType<>();
//        b.setData(new Fruit());//报错 只能放apple或apple的子类
        print2(b);
//        print2(new GenericType<Hongfushi>());//报错，向下我是有界限的

        GenericType<? super Apple> c1 = a;
        GenericType<? super Apple> c2 = b;
        GenericType<? super Apple> c = new GenericType<>();
        Apple apple = new Apple();
        Fruit fruit = new Fruit();
        Hongfushi hongfushi = new Hongfushi();
        //<? super Apple> 可以放apple或apple的子类
        c.setData(apple);
        c.setData(hongfushi);
        //用假设法来理解
        //为啥不能设fruit, 假定c泛型是Fruit, 那肯定是可以放， 但是如果c泛型是Apple，那肯定就不能放了，所以报错
//        c.setData(fruit);//报错
        Object a1 = c.getData();
    }
}
